package util;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * Represents the Contestants in the race. Contains the ID, name and the
 * category of the contestants as well as a list of TimePairs that contain all
 * times registered for this contestant.
 * 
 * Contestant is an abstract class which is extended in subclasses.
 * 
 * @author team07
 * 
 */
public abstract class Contestant {

	protected Map<Integer, TimePair> timePairs;
	protected int ID;
	protected String name;
	protected String category;

	/**
	 * Creates a Contestant with specified driver ID and empty time data
	 * 
	 * @param ID
	 *            the ID of the Contestant.
	 */
	public Contestant(int ID) {
		this.timePairs = new TreeMap<Integer, TimePair>();
		this.ID = ID;
		this.name = "n/a";
		this.category = "n/a";
	}

	/**
	 * Returns the ID of this contestant.
	 * 
	 * @return ID Returns the ID of this Contestant.
	 */
	public int getID() {
		return ID;
	}

	/**
	 * Returns the name of this Contestant.
	 * 
	 * @return name The name of the Contestant
	 */
	public String getName() {
		return name;
	}
	
	public abstract String errorString();

	/**
	 * Set the name to this Contestant
	 * 
	 * @param name
	 *            The Contestant as a String
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * Returns the group of this contestant.
	 * 
	 * @return The group of the contestant.
	 */
	public String getCategory() {
		return category;
	}

	/**
	 * Sets the category of the driver to the specified
	 * 
	 * @param category
	 *            The specified category
	 */
	public void setCategory(String category) {
		this.category = category.equals("") ? "n/a" : category;
	}

	/**
	 * Returns the internal list of TimePairs.
	 * 
	 * @return The list of TimePairs
	 */
	public List<TimePair> getAbsoluteTimes() {
		List<TimePair> tps = new ArrayList<TimePair>();
		tps.addAll(timePairs.values());
		return tps;
	}

	/**
	 * Returns the calculated TotalTime of the Contestant
	 * 
	 * @return The calculated total time
	 */
	public abstract long getTotalTime();

	/**
	 * Calculates the number of parts that this conetstant has taken part in.
	 * This means the number of laps OR the number of stages.
	 * 
	 * @return The number of parts
	 */
	public abstract int getNbrParts();

	/**
	 * Returns a string of the contestants' total time. This can contain text if
	 * there is an error with the time.
	 * 
	 * @return TotalTime as String
	 */
	public abstract String getTotalTimeString();

	/**
	 * Returns a string representating the contestant that can be used when
	 * printing an (sorted) ID list. The number of laps are used for padding
	 * with ';'.
	 * 
	 * @param nbrLaps
	 *            the total number of laps in the competition
	 * @return a very long string containing total number of laps information
	 */
	public abstract String toString_id(int nbrLaps);

	/**
	 * Returns a string representating the contestant that can be used when
	 * printing a position (sorted) list. The number of laps are used for
	 * padding with ';'.
	 * 
	 * @param nbrLaps
	 *            the total number of laps in the competition
	 * @return a very long string containing total number of laps information
	 */
	public abstract String toString_pos(int nbrLaps);

	/**
	 * Creates a list of all individual times of the parts relative to the start
	 * of the each part.
	 * 
	 * @return The relative times.
	 */
	public abstract List<Long> getRelativeTimes();

	/**
	 * Returns a string if the Contestant has got multiple starttimes, an
	 * impossible laptime or some other error that according to the
	 * specifications should be printed at the end of a results list
	 * 
	 * @return The errorstring generated
	 */
	protected abstract String getErrorString();

	/**
	 * Checks if the Object o is a contestant and if that contestants ID is the
	 * same as for this contestant.
	 * 
	 * @return True or false
	 */
	public boolean equals(Object other) {
		try {
			return (((Contestant) other).ID == this.ID);
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * Standard hashcode-function
	 * 
	 * @return The hashcode
	 */
	public int hashCode() {
		return this.ID;
	}
}